const _ = require('lodash');
const authedUser = require('../authed.json');
const config = require('../config');
// mkv格式不支持在线播放，所以暂时不返回mkv格式的视频，如果需要返回请使用上面的注释
const videoType = config.frontVideoType;
const imgType = config.imgType;
const ffmpeg = require('fluent-ffmpeg');
const { getVideoDurationInSeconds } = require('get-video-duration');
const qualityList = ['', '1920x1080', '1280x720', '640x480']
const fs = require('fs');
const encrypt = require('../encrypt');
const crypto = require('crypto');
const redisClient = require('../redis');
module.exports = {
  auth: function (req, res, next) {
    // 账密验证
    if (req.headers.authorization) {
      // 当在浏览器弹窗中输入账号密码点确定后，账号密码以:分割被 base64 加密后放在请求头中的 authorization 中
      const accountAndPasswordStr = Buffer.from(req.headers.authorization.replace(/Basic /g, ''), 'base64').toString();
      const accountAndPasswordArr = accountAndPasswordStr.split(':');
      const password = authedUser[accountAndPasswordArr[0]];
      if (typeof password != 'undefined' && accountAndPasswordArr[1] === password) {
        next();
        return;
      }
    }
    res.statusCode = 401;
    res.setHeader('WWW-Authenticate', 'Basic realm="Only for specific personnel"');
    res.end();
  },

  // 1、第一次打开走到这儿，返回登录页面
  simpleAuth: function (req, res, next) {
    // 8、前端刷新触发该 if 判断
    if (req.cookies.authId) {
      serveStatic(req, res, next);
      return;
    }
    res.header('Content-Type', 'text/html; charset=UTF-8')
    res.send((fs.readFileSync('./public/login2.html')));
    res.end()
  },

  // 12、访问首页，路径是 / 并且验证成功，会走到这儿，返回首页页面
  index: function (req, res, next){
    res.header('Content-Type', 'text/html; charset=UTF-8')
    res.send((fs.readFileSync('./public/index.html')))
    res.end();
  },

  // 2、登录页面输入账号，回车触发登录接口，验证通过，分配一个token
  login: function (req, res, next){
    const { loginName } = req.body;
    if (authedUser[loginName]) {
      // md5: loginName 和 当前时间戳 加盐 qwezxc
      // const randomString = crypto.createHmac('md5', 'qwezxc').update(`${loginName}${new Date().getTime()}`).digest('hex')
      // 上面那种不用了，因为没法记录是不是会员，randomString = 会员状态:登录名，将密文中的 / 替换为<|>，在解密的时候要替换回来
      const randomString = encrypt.rsaEncrypt(authedUser[loginName].memberStatus + ':' + loginName + ':' + new Date().getTime()).replace(/\//g, '<|>');
      res.cookie('authId', `/${loginName}/${randomString}`, {
        maxAge: 1000 * 60 * 60 * 24
      });
      // 3、通知 socket 把该用户的 token 存起来，同时删除该用户旧 token，如果是挤出，那么A用户 token 就会被删
      try {
        client.send(`Add:/${loginName}/${randomString}`)
      } catch (error) {
        console.log(error)
      }
      res.end();
      return;
    }
    res.statusCode = 403;
    res.end();
  },

  fileList: function(req, res, next) {
    const filteredPath = (req.query.path || '').split('/').filter(item => item).join('/')
    const start = filteredPath.startsWith('/');
    let files = [];
    switch (start) {
      case true:
        files = fs.readdirSync(`${staticPath}${filteredPath}`)
        res.send(files.filter(item => {
          const suffix = item.split('.');
          // 必须是视频类型、图片类型、否则就是文件夹，文件夹的话suffix只有一个元素，就是文件夹的名字，但是文件夹的名字不能是System Volume Information, $RECYCLE.BIN, version
          return (videoType.includes(suffix[suffix.length - 1].toLocaleLowerCase()) || suffix.length === 1 || imgType.includes(suffix[suffix.length - 1].toLocaleLowerCase())) && !(config.skipDirectory.includes(suffix[0]))
        }));
        break;
      case false:
        files = fs.readdirSync(`${staticPath}/${filteredPath}`)
        res.send(files.filter(item => {
          const suffix = item.split('.');
          // 必须是视频类型、图片类型、否则就是文件夹，文件夹的话suffix只有一个元素，就是文件夹的名字，但是文件夹的名字不能是System Volume Information, $RECYCLE.BIN, version
          return (videoType.includes(suffix[suffix.length - 1].toLocaleLowerCase()) || suffix.length === 1 || imgType.includes(suffix[suffix.length - 1].toLocaleLowerCase())) && !(config.skipDirectory.includes(suffix[0]))
        }));
        break;
      default:
        files = fs.readdirSync(`${staticPath}`)
        res.send(files.filter(item => {
          const suffix = item.split('.');
          // 必须是视频类型、图片类型、否则就是文件夹，文件夹的话suffix只有一个元素，就是文件夹的名字，但是文件夹的名字不能是System Volume Information, $RECYCLE.BIN, version
          return (videoType.includes(suffix[suffix.length - 1].toLocaleLowerCase()) || suffix.length === 1 || imgType.includes(suffix[suffix.length - 1].toLocaleLowerCase())) && !(config.skipDirectory.includes(suffix[0]))
        }));
        break;
    }
    return
  },

  imgPath: function(req, res, next) {
    const videoToImgPath = require('../videoToImg.json');
    res.send(videoToImgPath);
    res.end();
  },

  searchFun: function(req, res, next) {
    const { keyWords } = req.query;
    if (!keyWords) {
      res.send([]) && res.end();
      return;
    }
    const videoToImgPath = require('../videoToImg.json');
    // 搜索结果是包含凉森和破解的，或者是包含里美和39的
    // 空格符表示and，|表示或者
    function deepSearch(preResult, con, conditionArr){
      if (con) {
        return deepSearch(preResult.filter(item => item.toLowerCase().includes(con.toLowerCase())), conditionArr.shift(), conditionArr)
      }
      return preResult
    }
    const allVideo = Object.keys(videoToImgPath);
    // 假设传的keywords是 “凉森 破解|里美 39”
    // or就是 ['凉森 破解', '里美 39'], 遍历的时候 conditionArr 就是['凉森', '破解']，因为是传的shift函数执行后的结果，而conditionArr又是数组
    // 所以deepSearch的conditionArr是已经shift后的结果
    const or = keyWords.split('|');
    const orResult = [];
    for (let item of or) {
      const conditionArr = item.split(' ').filter(item => item);
      orResult.push(...(deepSearch(allVideo, conditionArr.shift(), conditionArr)))
    }
    res.send(orResult);
    deepSearch = null;
    res.end();
  },

  uploadFun:  function(req, res, next) {
    console.log(req.files);
    if (_.get(req, ['files', 'length']) && fs.existsSync(`${staticPath}/${req.files[0].originalname}`)) {
      console.log('不存在');
      const data = fs.readFileSync(req.files[0].path);
      fs.writeFileSync(`${staticPath}/${req.files[0].originalname}`, data);
    }
    console.log('end');
    res.end()
  },

  getVideo:  function(req, res, next) {
    const { filePath, startTime, quality } = req.query;
    if (!qualityList[quality]) return res.redirect(`/${filePath}`);
    res.setHeader('Content-Type', 'video/mp4');
    new ffmpeg(`./public/${filePath}`)
    // 支持在线播放
    .outputOptions(['-movflags isml+frag_keyframe'])
    // 要么使用outputOptions + format(mp4)要么使用format("h264")单独一行，但是 format h264是不能在线播放的
    // .format("h264")
    .format("mp4")
    .size(qualityList[quality])
    .seekInput(startTime || '0:0:0.000')
    .on('error', function(err, stdout, stderr) {
      res.end();
      console.log(err.message, stdout, stderr);
    })
    .on('end', function() {
      res.end()
      console.log('Processing finished !');
    })
    .pipe(res, { end: true });
  },

  getDuration: function(req, res, next) {
    const { filePath } = req.query;
    if (!filePath) return res.send('0');
    getVideoDurationInSeconds(`${filePath.startsWith('http') ? filePath : `./public/${filePath}`}`).then((duration) => {
      res.send(`${duration}`)
      res.end();
    });
  },

  getEncryptVideoM3u8: function (req, res) {
    const fsRes = fs.readFileSync('./public/encrypt/' + req.params.videoName + `/${config.m3u8Name}.m3u8`, 'utf-8')
    res.send(encrypt.rsaEncryptLargeText(fsRes))
    res.end()
  },

  getTsPlayList: async function(req, res, next) {
    const { encode, requestId } = req.query;
    if (!encode) return res.send('0');
    const unbase64b = Buffer.from(decodeURIComponent(encode), 'base64');
    const decrypted = encrypt.rsaDecrypt(unbase64b).toString();
    if (!decrypted.includes('playlist0.ts')) {
      if (requestId == undefined) return res.end('非法请求');
      const encryptRoleAndUsername = req.cookies.authId.split('/')
      // roleAndUsername = memberStatus:userName:timestamp
      const roleAndUsername = encrypt.rsaPublicDecrypt(decodeURIComponent(encryptRoleAndUsername[encryptRoleAndUsername.length - 1]).replace(/\<\|\>/g, '/')).toString()
      // account + movie
      const value = await redisClient.get(roleAndUsername.split(':')[1] + decrypted.split('/')[0] + '-random')
      if (value != requestId) return res.end('非法请求');
      await redisClient.del(roleAndUsername.split(':')[1] + decrypted.split('/')[0] + '-random')
    }
    if (req.cookies.authId) {
      serveStatic(req, res, next);
      return;
    }
  },

  getKeyFile: function(req, res, next) {
    const fsRes = fs.readFileSync('./public/encrypt.key', 'utf-8')
    res.end(encrypt.rsaEncrypt(fsRes))
  },

  getPemFile: function(req, res, next) {
    const fsRes = fs.readFileSync('./pem/myPublic.pem', 'utf-8')
    const charCode = [];
    for (const str of fsRes) {
      charCode.push(str.charCodeAt() * 11)
    }
    res.end(charCode.join())
  },
}